package com.atguigu.guli.service.trade.service.impl;

import com.atguigu.guli.common.util.utils.HttpClientUtils;
import com.atguigu.guli.common.util.utils.OrderNoUtils;
import com.atguigu.guli.common.util.utils.StreamUtils;
import com.atguigu.guli.service.base.dto.CourseInfoDto;
import com.atguigu.guli.service.base.dto.MemberDto;
import com.atguigu.guli.service.base.exception.GuliException;
import com.atguigu.guli.service.base.result.R;
import com.atguigu.guli.service.base.result.ResultCodeEnum;
import com.atguigu.guli.service.trade.entity.Order;
import com.atguigu.guli.service.trade.entity.PayLog;
import com.atguigu.guli.service.trade.mapper.OrderMapper;
import com.atguigu.guli.service.trade.properties.WxPayProperties;
import com.atguigu.guli.service.trade.service.EduFeignClient;
import com.atguigu.guli.service.trade.service.OrderService;
import com.atguigu.guli.service.trade.service.PayLogService;
import com.atguigu.guli.service.trade.service.UcenterFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.wxpay.sdk.WXPayUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 订单 服务实现类
 * </p>
 *
 * @author atguigu
 * @since 2021-08-13
 */
@Service
@Transactional //多个sql更新操作 必须同时成功才会被提交
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
    @Autowired
    EduFeignClient eduFeignClient;
    @Autowired
    UcenterFeignClient ucenterFeignClient;

    @Override
    public String createOrder(String memberId, String courseId) {
        //判断当前用户是否已经购买课程
        LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Order::getCourseId,courseId);
        queryWrapper.eq(Order::getMemberId,memberId);
        Order oldOrder = baseMapper.selectOne(queryWrapper);
        //判断该课程当前用户是否存在未支付的订单
        if (oldOrder!=null && oldOrder.getStatus()==1){
            //用户已经购买过该课程并支付完成
            throw new GuliException(ResultCodeEnum.ORDER_EXIST_ERROR);
        }

        //远程访问service-edu微服务查询课程详情
        R courseDtoR = eduFeignClient.getCourseDto(courseId);
        if (!courseDtoR.getSuccess()){
            throw new GuliException(ResultCodeEnum.PAY_UNIFIEDORDER_ERROR);
        }
        Object courseDtoObj = courseDtoR.getData().get("item");
        ObjectMapper mapper = new ObjectMapper();//可以转换对象，把map类型转换为指定类型的对象
        //通过json转换的方式把courseDtoObj 转换为CourseInfoDto对象
        CourseInfoDto courseInfoDto = mapper.convertValue(courseDtoObj, CourseInfoDto.class);

        //可以将map转为Dto对象：java.util.LinkedHashMap
        System.out.println("courseDtoObj: " + courseDtoObj.getClass().getName());
        //需要访问service-ucenter微服务  获取用户详情
        R memberDtoR = ucenterFeignClient.getMemberDto(memberId);
        if (!memberDtoR.getSuccess()){
            throw new GuliException(ResultCodeEnum.PAY_UNIFIEDORDER_ERROR);
        }
        Object memberDtoObj = memberDtoR.getData().get("item");
//        System.out.println("memberDtoObj:" + memberDtoObj.getClass().getName());
        MemberDto memberDto = mapper.convertValue(memberDtoObj, MemberDto.class);

        Order order = new Order();
        order.setStatus(0);//支付状态，0代表未支付
        order.setTeacherName(courseInfoDto.getTeacherName());
        /*
        课程的价格村的时候使用的单位是元，存到数据库中的数据会存在小数，一定有精度问题

        为了保证金额没有精度问题，可以以单位分来存储金额，没有小数
         */
        //将元转为分
        long price = courseInfoDto.getPrice().multiply(new BigDecimal("100")).longValue();
        order.setTotalFee(price);
        order.setCourseCover(courseInfoDto.getCover());
        order.setCourseTitle(courseInfoDto.getTitle());
        order.setCourseId(courseId);

        order.setMobile(memberDto.getMobile());
        order.setNickname(memberDto.getNickname());
        order.setMemberId(memberId);
        order.setOrderNo(OrderNoUtils.getOrderNo());
        if (oldOrder!=null && oldOrder.getStatus()==0){
            //如果存在未支付的订单 ，本次更新
            order.setId(oldOrder.getId());
            order.setOrderNo(oldOrder.getOrderNo());
            baseMapper.updateById(order);
        }else {
            //如果是新创建的订单  本次新增
            baseMapper.insert(order);
        }
        return order.getId();
    }
    @Autowired
    PayLogService payLogService;
    @Autowired
    WxPayProperties wxPayProperties;

    @Override
    public String nofityurl(HttpServletRequest request) {
        Map returnMap = new HashMap();//用来存放给微信的响应数据
        returnMap.put("return_code","FAIL");
        returnMap.put("return_msg","FAIL");
        try {
            //wx传入的用户支付的结果
            String callbackStr = StreamUtils.inputStream2String(request.getInputStream(), "UTF-8");
            //验证签名是否正确
            boolean signatureValid = WXPayUtil.isSignatureValid(callbackStr, wxPayProperties.getPartnerKey());
            if(!signatureValid){
//               throw new GuliException(ResultCodeEnum.ILLEGAL_CALLBACK_REQUEST_ERROR);
                returnMap.put("return_msg","签名失败");
                return WXPayUtil.mapToXml(returnMap);
            }
            // 验证用户实付金额和订单是否一致
            Map<String, String> map = WXPayUtil.xmlToMap(callbackStr);
            System.out.println(map);
            if(!"SUCCESS".equals(map.get("return_code"))){
//               throw new GuliException(ResultCodeEnum.ILLEGAL_CALLBACK_REQUEST_ERROR);
                returnMap.put("return_msg","响应失败");
                return WXPayUtil.mapToXml(returnMap);
            }
            String cash_fee = map.get("cash_fee");//用户支付金额
            String out_trade_no = map.get("out_trade_no");//订单编号
            //查询数据库中订单的金额
            LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Order::getOrderNo , out_trade_no);
            Order order = this.getOne(queryWrapper);
            if(order==null || order.getTotalFee()!=Long.parseLong(cash_fee)){
//               throw new GuliException(ResultCodeEnum.ILLEGAL_CALLBACK_REQUEST_ERROR);
                returnMap.put("return_msg","用户支付金额和订单金额不一致");
                return WXPayUtil.mapToXml(returnMap);
            }
            //订单支付成功
            //更新订单状态
            if(order.getStatus()==0){//订单状态未更新
                LambdaUpdateWrapper<Order> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.set(Order::getStatus , 1);//支付状态 1代表已支付
                updateWrapper.set(Order::getPayType , 1);//支付类型
                this.update(updateWrapper);
                //保存订单支付日志
                PayLog payLog = new PayLog();
                payLog.setPayType(1);
                payLog.setPayTime(new Date());
                payLog.setTotalFee(order.getTotalFee());
                payLog.setOrderNo(order.getOrderNo());
                payLog.setTradeState("1");
                payLog.setTransactionId(map.get("transaction_id"));
                payLog.setAttr(callbackStr);
                payLogService.save(payLog);
                //更新课程销量：远程访问service-edu更新课程表课程的销量
                eduFeignClient.updateSales(order.getCourseId());

            }
            returnMap.put("return_code","SUCCESS");
            returnMap.put("return_msg","OK");
            return WXPayUtil.mapToXml(returnMap);
        } catch (Exception e) {
//           e.printStackTrace();
//            throw new GuliException(ResultCodeEnum.ILLEGAL_CALLBACK_REQUEST_ERROR,e);
//           returnMap.put("return_code","SUCCESS");
            returnMap.put("return_msg","出现异常");
            try {
                return WXPayUtil.mapToXml(returnMap);
            } catch (Exception ex) {
                throw new GuliException(ResultCodeEnum.ILLEGAL_CALLBACK_REQUEST_ERROR,e);
            }
        }
    }

    @Override
    public R createNative(String orderId, HttpServletRequest request) {
        try {
            Order order = this.getById(orderId);
            //访问wx的统一下单接口并配置参数
            String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
            //wx提供了一个sdk包  提供了将xml转为map  将map转为xml格式的 工具类方法
            //为网络请求准备参数
            HashMap<String, String> map = new HashMap<>();
            map.put("appid",wxPayProperties.getAppId());//wx平台分配的应用的id
            map.put("mch_id",wxPayProperties.getPartner());//使用wx平台为商户分配的编号
            map.put("nonce_str",WXPayUtil.generateNonceStr());//随机字符串
//        map.put("sign",""); // 保证数据安全不会被篡改
            map.put("body",order.getCourseTitle());//展示给wx用户的商品 信息
            map.put("out_trade_no",order.getOrderNo());//订单编号
            map.put("total_fee",order.getTotalFee()+"");

            map.put("spbill_create_ip",request.getRemoteHost());//客户端ip地址
            map.put("notify_url",wxPayProperties.getNotifyUrl());//用户扫描本次生成的二维码支付成功后的回调
            map.put("trade_type","NATIVE");//本次是web项目的支付
//        WXPayUtil.mapToXml()
//                WXPayUtil.xmlToMap()
            //指定秘钥 根据map生成签名
            String signedXmlStr = WXPayUtil.generateSignedXml(map, wxPayProperties.getPartnerKey());

            //发起网络请求并将xml作为参数传入
            HttpClientUtils client = new HttpClientUtils(url);
            System.out.println(signedXmlStr);
            client.setXmlParam(signedXmlStr);
            client.post();

            String content = client.getContent();

            boolean signatureValid = WXPayUtil.isSignatureValid(content, wxPayProperties.getPartnerKey());
            if(!signatureValid){
                //签名或数据被篡改
                throw new GuliException(ResultCodeEnum.PAY_UNIFIEDORDER_ERROR);
            }
            Map<String, String> resultMap = WXPayUtil.xmlToMap(content);
            System.out.println("resultMap = " + resultMap);
            if(!"SUCCESS".equals(resultMap.get("return_code"))  ||
                    !"SUCCESS".equals(resultMap.get("result_code"))
            ){
                //wx响应失败
                throw new GuliException(ResultCodeEnum.PAY_UNIFIEDORDER_ERROR);
            }
            String codeUrl = resultMap.get("code_url");
            //返回二维码连接  前端页面获取后可以转换为二维码图片显示到页面中（guli-site 的 pay/_id页面）
            return R.ok().data("code_url" , codeUrl)
                    .data("out_trade_no",order.getOrderNo())
                    .data("total_fee",order.getTotalFee())
                    .data("courseId",order.getCourseId())
                    .data("orderId" , order.getId());
        } catch (Exception e) {
            throw new GuliException(ResultCodeEnum.PAY_UNIFIEDORDER_ERROR,e);
        }

    }
}
